/*
 * MLscheduler.cpp
 *
 *  Created on: Jun 28, 2009
 *      Author: yanir
 */


#include "MLscheduler.h"

/* C'tor  */
	MLscheduler::MLscheduler(){}

	MLscheduler::MLscheduler(int quanta,map<string, Worker>* workers ,Mailer* mailer){

		m_contex_switch_count = 0;
		m_quanta_count = 0;
		m_msg_passed_count = 0;
		m_phase_count = 0;


		m_mailer = mailer;
		m_workers = workers;
		m_quanta = quanta;


		m_switch_queue = false;

		for (int i=0;i<3;i++) {
				RRscheduler* rrQueue = new RRscheduler(m_quanta,m_workers,m_mailer);
				m_p_queues.push_back(rrQueue);
		}

		for (int i=0;i<2;i++) {
				m_p_queues[i]->emptyQueues();
		}




		m_current_queue = 3;  /* the queue with the lowest priority */

		//m_users_in_queue = 0;


	}


	MLscheduler::~MLscheduler(){}




	int MLscheduler::getQuanta(){
		return m_quanta;
	}



	void MLscheduler::incCScount(){
		m_contex_switch_count++;

	}


	void MLscheduler::incQuantaCount(){
		m_quanta_count++;
	}

	void MLscheduler::incMsgPass(){
		m_msg_passed_count++;
	}


	///////////////////////// Basic Functions /////////////////////////////////////

	bool MLscheduler::isStable(){

		bool ans = true;
		for (int i=0;i<3;i++) {
				ans = ((m_p_queues[i]->isStable()) & ans);
		 }

		return ans;
	}

	void MLscheduler::printSum(){
		int sum = 0;

		for (int i = 0; i<3 ; i++){
			sum =+ m_p_queues[i]->getTotalCS();
		}

		cout << " SUMMARY of scheduling iteration : \n" ;
		cout << " - number of context switches :\t" << m_contex_switch_count +sum <<"\n";

		sum = 0;
		for (int i = 0; i<3 ; i++){
					sum =+ m_p_queues[i]->getQuanta();
		}
		cout << " - message quanta given :\t" << m_quanta_count <<"\n";

		sum = 0;
		for (int i = 0; i<3 ; i++){
							sum =+ m_p_queues[i]->getTotalMsg();
		}

		cout << " - message passed  :\t" << m_msg_passed_count <<"\n";
		cout << " - thread tables : \n";
		cout << "\t ID \t\t STATUS \t\t MSG_DELIVERED \t\t MSG_TOTAL \t\t PRIORITY \n ";
	/*	threadsTable::iterator iter;
		for(iter = m_tT->begin() ; iter != m_tT->end() ;++iter){
			cout << "\t " << iter->first ;
			cout << "\t\t " << iter->second.status;
			cout << "\t\t " << iter->second.accuMessQua;
			cout << "\t\t\t " << iter->second.totMessQua;
			cout << iter->second.priority << " \n" ;
		}*/

	}



	void MLscheduler::init(){

	}



	void MLscheduler::nextWorker(){

			switchQueue(m_p_queues[m_current_queue]);
			m_p_queues[m_current_queue]->nextWorker();
			switchQueue(m_p_queues[m_current_queue]);
	}



	///////////////////////// Additional Multi level scheduler functions /////////////////

	void MLscheduler::switchQueue(RRscheduler* current_queue){

		//if the round didn't end
		if(!m_switch_queue){
			m_users_in_queue = current_queue->getActiveThreadsSize();


		if(m_users_in_queue  > 0) {
				m_switch_queue = false;
			//	current_queue->nextWorker();
				m_users_in_queue--;
		}
		//the round ended
		else
		{
				this->incCScount();
				m_switch_queue = true;
				m_current_queue = ((m_current_queue + 1) % 4);
				changePriorities(current_queue);
		}
	}
	}


	void MLscheduler::changePriorities(RRscheduler* current_queue){

		vector<Worker*> usersVector = getQueueUsers(current_queue);
		double usage;
		int workerQuanta;

		if (!usersVector.empty()){

			for(unsigned int i = 0; i < usersVector.size() ; i++){

				Worker* worker = usersVector.back();
				usersVector.pop_back();
				workerQuanta = worker->getQuanta();
				usage = ((m_quanta - workerQuanta) / m_quanta);   		//((m_quantum - (worker->getQuanta()))/m_quantum);

				// all quanta was use - promote worker//
				if (usage == 1){
					//if in the 3rd priority queue //
					if(m_current_queue == 1){
						m_p_queues[0]->getActiveThreads()->push(worker);
					}else{
						m_p_queues[m_current_queue - 1]->getActiveThreads()->push(worker);
					}

				}else{
						// no change //
						if ( (usage == 0) | (usage >= 0.5) ){
								m_p_queues[m_current_queue]->getActiveThreads()->push(worker);

						// demote worker //
						}else{
								if(m_current_queue == 3){
									m_p_queues[m_current_queue]->getActiveThreads()->push(worker);
								}else
									m_p_queues[m_current_queue + 1]->getActiveThreads()->push(worker);

							}
				}

		}

	}
}


	vector<Worker*> MLscheduler::getQueueUsers(RRscheduler* current_queue){

			vector<Worker*> tempVec;
			vector<Worker*> ansVec;
			Worker* worker;

			while (!current_queue->getActiveThreads()->empty()){

				worker = current_queue->getActiveThreads()->front();
				current_queue->getActiveThreads()->pop();
				tempVec.push_back(worker);

			}

			//////////////////////////////////////////////
			// test :
			cout<< "testing :  users vector before :  "<< endl;

			for(unsigned int i = 0; i < tempVec.size() ; i++){
				cout <<" " << tempVec[i]->getMyID();
			}
			cout << endl;


			/////////////////////////////////////////////

			while (!tempVec.empty()){
				ansVec.push_back(tempVec.back());
				tempVec.pop_back();

			}
			///////////////////////////////////////////////

			cout<< "testing :  users vector after :  "<< endl;

					for(unsigned int i = 0; i < ansVec.size() ; i++){
						cout <<" " << ansVec[i]->getMyID();
					}
					cout << endl;
			/////////////////////////////////////////
			return ansVec;

	}


